package com.otherTest.properties;

import java.io.BufferedReader;



import org.springframework.util.ObjectUtils;

import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.*;
import java.lang.Boolean;
import java.lang.Double;
import java.lang.Exception;
import java.lang.Integer;
import java.lang.NullPointerException;
import java.lang.String;
import java.lang.StringBuffer;
import java.util.Enumeration;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * 读取properties配置文件
 * <p>
 * <p>
 * 增加可读取array功能
 * 对空数组,String单下标的数组,多下标String数组做到可识别读取
 * 对数字支持int,double的array支持
 * <p>
 * 混合数组整型优先返回,否则按照double处理，其他情况按照String处理
 * 对单个的属性值支持自动装箱与拆箱,intArray与doubleArray不支持自动装箱与拆箱
 * <p>
 * String的双引号带不带都可以,默认的分隔符与array保持一致
 * 兼容汉字 防止原生的getValue 出现的中文乱码情况
 *
 * @author Conceit
 *         2017-08-21 添加方法 getPropertiesByClassLoader
 *         2017-08-21 添加方法 getPropertiesByClassLoader
 *         2017-08-21 添加方法 readPropertiesFile
 *         2017-08-21 添加方法 adapterPropertyValue
 *         2017-08-21 添加方法 convertProperties
 *         2017-08-21 添加方法 convertProperty
 *         2017-08-21 添加方法 convertFileToInputStream
 *         2017-08-21 添加方法 stringIsArray
 *         2017-08-21 添加方法 stringConvertChartSet
 *         2017-08-21 添加方法 stringConvertArray
 *         2017-08-21 添加方法 stringSegmentByCharacter
 *         2017-08-21 添加方法 stringArrayTrimCharacterByCharacter
 *         2017-08-21 添加方法 stringTrimCharacterByCharacter
 *         2017-08-21 添加方法 stringIsNumeric
 *         2017-08-21 添加方法 stringIsString
 *         2017-08-21 添加方法 stringArrayIsNumericArray
 *         2017-08-21 添加方法 stringArrayIsStringArray
 *         2017-08-21 添加方法 stringArrayIsIntegerArray
 *         2017-08-21 添加方法 stringArrayIsDoubleArray
 *         2017-08-21 添加方法 stringIsInteger
 *         2017-08-21 添加方法 convertStringToInteger
 *         2017-08-21 添加方法 convertStringArrayToIntegerArray
 *         2017-08-21 添加方法 convertStringArrayToDoubleArray
 *         2017-08-21 添加方法 convertStringToDouble
 * @since 1.0.0, 2017/08/21
 */
//@Configuration
//@Bean
public class ReadPropertiesUtil {

    /**
     * 定义常量参数
     */
    //数组前缀
    private static final String ARRAY_PREFIX = "[";
    //数组后缀
    private static final String ARRAY_POSTFIX = "]";
    //数组分隔符
    private static final String ARRAY_SEPARATOR = ",";
    //数组默认解析字符编码
    private static final String ARRAY_DEFAULT_CHARTSET = "UTF-8";
    //数字小数点
    private static final String RADIX_POINT = ".";
    //引号
    private static final String QUOTATION_MARK = "\"";
    //数学加号
    private static final String PULS_SIGN = "+";
    //数学减号
    private static final String MINUS_SIGN = "-";
    //正则数字判断规则(包含浮点以及整数类型)
    private static final String IS_NUMERIC_RULE = "^[-\\+]?[.\\d]*$";
    //正则数字判断是否为整型
    private static final String IS_INTEGER_NUMERIC_RULE = "^[-\\+]?[\\d]*$";

    /**
     * 通过类加载器获取资源文件
     * <p>
     * 从classpath下获取资源文件
     * 如果存在父级目录可以指定为参数
     * <p>
     * class.getResourceAsStream("");为获取class所在包下的资源
     * class.getResourceAsStream("/");为获取classPath包下的资源
     * class.getClassLoader().getResourceAsStream("");为获取classPath下的资源文件
     *
     * @param propertiesName 资源文件名
     * @return InputStream 流
     */
    public InputStream getPropertiesByClassLoader(String propertiesName) throws Exception {
        InputStream inputStream = null;
        try {
            File file = new File(this.getClass().getClassLoader().getResource(propertiesName).getFile());
        } catch (NullPointerException e) {
            throw new NullPointerException("没有此文件对象");
        }


        return this.getClass().getClassLoader().getResourceAsStream(propertiesName);
    }

    /**
     * 通过类加载器获取资源文件 方法重载 可以指定其父级目录
     *
     * @param parentName     父级目录
     * @param propertiesName 资源文件名
     * @return InputStream
     */
    public InputStream getPropertiesByClassLoader(String parentName, String propertiesName) throws Exception {
        if (parentName == null || parentName.equalsIgnoreCase("")) {
            throw new NullPointerException("ParentName文件名无效");
        }
        if (propertiesName == null || propertiesName.equalsIgnoreCase("")) {
            throw new NullPointerException("propertiesName文件名无效");
        }
        File parentFile = null;
        try {
            parentFile = new File(this.getClass().getClassLoader().getResource(parentName).getFile());
        } catch (NullPointerException e2) {
            throw new NullPointerException("没有此父类文件夹");
        }
        if (parentFile.isDirectory()) {
            File[] files = parentFile.listFiles();
            for (int i = 0; i < files.length; i++) {
                if (files[i].getName().equalsIgnoreCase(propertiesName)) {
                    return convertFileToInputStream(files[i]);
                }
            }
        }
        return null;
    }

    /**
     * 读取配置文件总入口
     * 将配置文件名和
     *
     * @param propertiesName 文件名
     * @param propertyName   参数名
     * @return <T>
     * @throws NullPointerException
     * @throws FileNotFoundException
     */
    public <T> T readPropertiesFile(String propertiesName, String propertyName) throws Exception {

        if (propertiesName == null || propertiesName.equalsIgnoreCase("")) {
            throw new NullPointerException("传入的文件名无效");
        }

        //加载文件
        InputStream inputStream = new ReadPropertiesUtil().getPropertiesByClassLoader(propertiesName);
        //字节流无法读取中文
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        Properties properties = new Properties();
        properties.load(bufferedReader);

        //属性名合法化判断
        if (!properties.containsKey(propertyName)) {
            throw new NullPointerException("没有对应传入的propertyName");
        }

        //获取对应的value
        String propertyValue = properties.getProperty(propertyName);


        //调用转换属性值方法并返回
        return (T) adapterPropertyValue(propertyValue);
    }


    /**
     * adapterPropertyValue
     * 核心方法对propertyValue 具体执行转换属性值的方法
     * String 转换为int,double,array,list,或者其他数据类型
     * propertyValue 具体执行转换属性值的方法
     *
     * @param propertyValue 配置文件中value
     * @return <T>
     */
    public <T> T adapterPropertyValue(String propertyValue) throws Exception {

        if (propertyValue == null) {
            throw new NullPointerException("传入的propertyValue为null");
        }

        if (propertyValue instanceof String) {

            //转换字符编码  此方法暂时无用
            //propertyValue = stringConvertChartSet(propertyValue, ARRAY_DEFAULT_CHARTSET);

            //检查是否为数组
            Boolean isArray = stringIsArray(propertyValue);
            //是否为数组
            if (isArray == true) {
                //分隔为StringArray
                String[] stringArray = stringConvertArray(propertyValue, ARRAY_SEPARATOR);
                //删除传入的多余字符(引号)
                stringArray = stringArrayTrimCharacterByCharacter(stringArray, QUOTATION_MARK);
                //调用方法判断是否全部为Numeric
                boolean isNumericArray = stringArrayIsNumericArray(stringArray);
                //判断是否全部为整数类型
                if (isNumericArray) {

                    if (stringArrayIsIntegerArray(stringArray)) {
                        int[] intArray = convertStringArrayToIntegerArray(stringArray);
                        return (T) intArray;
                    }

                    //如果包含小数点则全部为浮点型
                    if (stringArrayIsDoubleArray(stringArray)) {
                        double[] doubleArray = convertStringArrayToDoubleArray(stringArray);
                        return (T) doubleArray;
                    }

                }
                //如果不是则为StringArray
                else
                    return (T) stringArray;

            }
            //非数组
            //是否为Numeric
            boolean isNumeric = stringIsNumeric(propertyValue);
            if (isNumeric) {

                //整数类型
                if (stringIsInteger(propertyValue)) {
                    //泛型不支持基本数据类型
                    java.lang.Integer intValue = convertStringToInteger(propertyValue);
                    return (T) intValue;
                }
                //浮点型
                if (stringIsDouble(propertyValue)) {
                    //泛型不支持基本数据类型
                    Double doubleValue = convertStringToDouble(propertyValue);
                    return (T) doubleValue;
                }
            }
            //按string处理
            return (T) propertyValue;
        }


        return null;
    }


    /**
     * 转换配置文件属性
     *
     * @param properties 配置文件
     * @return 返回类型
     */
    public void convertProperties(Properties properties) {
        Enumeration<?> propertyNames = properties.propertyNames();
        while (propertyNames.hasMoreElements()) {
            String propertyName = (String) propertyNames.nextElement();
            String propertyValue = properties.getProperty(propertyName);
            String convertedValue = convertProperty(propertyName, propertyValue);
            if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) {
                properties.setProperty(propertyName, convertedValue);
            }
        }
    }

    /**
     * 具体的转换配置文件属性方法
     *
     * @param propertyName  key
     * @param propertyValue value
     * @return 返回类型
     */
    public String convertProperty(String propertyName, String propertyValue) {
        return null;
    }


    /**
     * 转换file为InputStream
     *
     * @param file
     * @return InputStream
     * @throws NullPointerException 输入的文件为空
     */
    public synchronized InputStream convertFileToInputStream(File file) throws FileNotFoundException {
        if (file == null) {
            throw new NullPointerException("文件无效");
        }
        //convertFileToInputStream
        InputStream inputStream = new FileInputStream(file);
        return inputStream;
    }

    /**
     * 判断是否为数组
     * string 需要包含 [   ]  且以[开头 且以 ] 结尾
     *
     * @param str 源String
     * @return boolean
     * @throws NullPointerException 输入的str为空
     */
    public boolean stringIsArray(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("需要判断是否为Array的String为Null");
        }
        //必须包含[ ]字符
        if (str.contains(ARRAY_PREFIX) && str.contains(ARRAY_POSTFIX)) {
            //以[开头 且以] 结尾
            if (str.startsWith(ARRAY_PREFIX) && str.endsWith(ARRAY_POSTFIX)) {
                return true;
            }

        }

        return false;
    }

    /**
     * String转换编码
     *
     * @param str      源String
     * @param chartSet 想要的字符集
     * @return String
     * @throws UnsupportedEncodingException 传入不支持的字符集
     */
    public String stringConvertChartSet(String str, String chartSet) throws UnsupportedEncodingException {
        if (str == null || str.equalsIgnoreCase("")) {
            return null;
        }
        //如果没有指定字符集，返回源String
        if (chartSet == null || chartSet.equalsIgnoreCase("")) {
            return str;
        }
        //以传入的字符集获取传入的String字符集
        byte[] strArray = str.getBytes(chartSet);
        return new String(strArray, chartSet);
    }

    /**
     * String转换为array数组
     *
     * @param separator 分割符
     * @param str       源String
     * @return String[]
     * @throws NullPointerException 输入的String为空
     */
    public String[] stringConvertArray(String str, String separator) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("需要转换的String为Null");
        }
        //多下标result
        String[] multipleResult;
        //单下标result
        String[] aloneResult = new String[1];
        //截取String[+1 到
        str = str.substring(str.indexOf(ARRAY_PREFIX) + 1, str.lastIndexOf(ARRAY_POSTFIX));
        //判断String是否含有 分割 字符 没有则直接放入Array,有则继续拆分循环放入Array
        //处理字符分割 拼接为array
        if (!str.contains(separator)) {
            aloneResult[0] = str;
            return aloneResult;
        } else {
            multipleResult = stringSegmentByCharacter(str, separator);
            return multipleResult;
        }


    }

    /**
     * String按照特定字符分割为array数组
     * 如果字符为null则原样返回String
     * split 方法注意 “.”和“|”都是转义字符,必须得加"\\";
     *
     * @param str       源String
     * @param separator 分割符
     * @return String[]
     * @throws NullPointerException 输入的String为空
     */
    public String[] stringSegmentByCharacter(String str, String separator) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("需要分割的String为Null");
        }
        String[] result = null;
        result = str.split(separator);
        return result;
    }

    /**
     * StringArray删除特定字符
     * 如果字符为null则原样返回StringArray
     * <p>
     * <p>
     * 循环每一个数组元素先将string转换成stringBuffer,
     * 循环每一个字符下标,如果相同就使用stringBuffer的deleteCharAt方法删除自定字符
     * <p>
     * 如果传入的数组为null或者下标数为0 ，传入的字符为null则直接返回
     *
     * @param strArray  源StringArray
     * @param character 指定字符
     * @return String[]
     */
    public String[] stringArrayTrimCharacterByCharacter(String[] strArray, String character) {
        if (strArray == null || strArray.length == 0) {
            return strArray;
        }
        if (character == null || character.equalsIgnoreCase("")) {
            return strArray;
        }
        for (int i = 0; i < strArray.length; i++) {
            try {
                strArray[i] = stringTrimCharacterByCharacter(strArray[i], character);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return strArray;
    }


    /**
     * String删除特定字符
     * 如果字符为null则原样返回String
     * <p>
     * <p>
     * 先将string转换成stringBuffer,
     * 循环每一个字符下标,如果相同就使用stringBuffer的deleteCharAt方法删除自定字符
     * 最后调用toString() 返回结果
     *
     * @param str       源String
     * @param character 指定字符集
     * @return String
     * @throws NullPointerException 输入的String为空
     */
    public String stringTrimCharacterByCharacter(String str, String character) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要删除特定字符的String为Null");
        }
        if (character == null || character.equalsIgnoreCase("")) {
            return str;
        }
        StringBuffer stringBuffer = new StringBuffer(str);
        int index;

        do {
            index = stringBuffer.indexOf(character);
            if (index != -1) {
                stringBuffer.deleteCharAt(index);
            }
        } while (index != -1);

        return stringBuffer.toString();
    }

    /**
     * String是否为NUMERIC
     * 正则表达式匹配
     * 只要有一个字符为非数字 小数点 正负 就为String
     *
     * @param str 源String
     * @return boolean false-该String为非数字类型(String)
     * @throws NullPointerException 输入的String为空
     */
    public boolean stringIsNumeric(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要判断是否为String为Null或者为空");
        }
        String isNumericRule = IS_NUMERIC_RULE;
        String isIntegerNumericRule = IS_INTEGER_NUMERIC_RULE;
        //创建正则表达式 忽略大小写
        Pattern pattern1 = Pattern.compile(isNumericRule, Pattern.CASE_INSENSITIVE);
        //String转char数组
        char[] strArray = str.toCharArray();
        for (char aStrArray : strArray) {
            //执行正则表达式
            boolean result1 = pattern1.matcher(String.valueOf(aStrArray)).matches();
            if (!result1) {
                return false;
            }
        }
        return true;
    }

    /**
     * String是否为String
     * 正则表达式匹配
     * 只要有一个字符为非数字 小数点 正负 就为String
     *
     * @param str 源String
     * @return boolean false-该String为非String类型
     * @throws NullPointerException 输入的String为空
     */
    public boolean stringIsString(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要判断是否为String为Null");
        }
        String isNumericRule = IS_NUMERIC_RULE;
        //创建正则表达式 忽略大小写
        Pattern pattern1 = Pattern.compile(isNumericRule, Pattern.CASE_INSENSITIVE);
        //String转char数组
        char[] strArray = str.toCharArray();
        for (int i = 0; i < strArray.length; i++) {
            //执行正则表达式
            boolean result1 = pattern1.matcher(String.valueOf(strArray[i])).matches();
            if (result1 == false) {
                return true;
            }
        }
        return false;
    }


    /**
     * 检测String数组是否全部为数字数组
     * 正则表达式匹配
     * 只要有一个字符为非数字 小数点 正负 就为StringArray
     *
     * @param strArray 源String数组
     * @return boolean false-该StringArray全部为String类型,或该Array的length为0
     * @throws NullPointerException 输入的String为空
     */
    public boolean stringArrayIsNumericArray(String[] strArray) throws Exception {
        if (strArray == null) {
            throw new NullPointerException("传入需要判断是否为StringArray为Null");
        }
        if (strArray.length == 0) {
            return false;
        }
        for (int i = 0; i < strArray.length; i++) {
            boolean result = stringIsNumeric(strArray[i]);
            if (result == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检测String数组是否全部为String数组
     *
     * @param strArray 源String数组
     * @return boolean false-该StringArray全部为false类型,或该Array的length为0
     * @throws NullPointerException 输入的StringArray为空
     */
    public boolean stringArrayIsStringArray(String[] strArray) throws Exception {
        if (strArray == null) {
            throw new NullPointerException("传入需要判断是否为StringArray为Null");
        }
        if (strArray.length == 0) {
            return false;
        }

        for (int i = 0; i < strArray.length; i++) {
            boolean result = stringIsString(strArray[i]);
            if (result == false) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检测数字Array是否全部为整型Array
     * <p>
     * 只要有一个字符为小数点则该数字类型则不为整型
     * 或者数字超过int的上限或低于int的下限
     * Integer 在解析时已经将上限下限小数点以及0开头的数字去0操作
     *
     * @param strArray 源String数组
     * @return boolean true-该StringArray全部为整数类型
     * @throws NullPointerException 输入的StringArray为空
     */
    public boolean stringArrayIsIntegerArray(String[] strArray) throws Exception {
        if (strArray == null) {
            throw new NullPointerException("传入需要判断是否为StringArray为Null");
        }
        for (int i = 0; i < strArray.length; i++) {
            boolean result = stringIsInteger(strArray[i]);
            if (result == false) {
                return false;
            }
        }

        return true;
    }

    /**
     * 检测数字Array是否全部为浮点型Array
     * <p>
     * 只要有一个字符为小数点则该数字类型则不为整型
     * 或者数字超过int的上限或低于int的下限
     * Integer 在解析时已经将上限下限小数点以及0开头的数字去0操作
     *
     * @param strArray 源String数组
     * @return boolean true-该StringArray全部为double类型
     * @throws NullPointerException 输入的StringArray为空
     */
    public boolean stringArrayIsDoubleArray(String[] strArray) throws Exception {
        if (strArray == null) {
            throw new NullPointerException("传入需要判断是否为StringArray为Null");
        }
        for (int i = 0; i < strArray.length; i++) {
            boolean result = stringIsDouble(strArray[i]);
            if (result == false) {
                return false;
            }
        }

        return true;
    }

    /**
     * 测数字是否为整型
     * <p>
     * 只要有一个字符为小数点则该数字类型则不为整型
     * 或者数字超过int的上限或低于int的下限
     * Integer 在解析时已经将上限下限小数点以及0开头的数字去0操作
     *
     * @param str 源String
     * @return boolean true-该String为整数类型
     * @throws NullPointerException 输入的String为空
     */
    public boolean stringIsInteger(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要判断是否为String为Null");
        }
        //小数点提前判断
        if (str.contains(RADIX_POINT)) {
            return false;
        }
        Integer intStr = null;
        try {
            intStr = intStr.parseInt(str);
        } catch (Exception e) {
            return false;
        }
        if (intStr == null) {
            return false;
        }
        return true;
    }

    /**
     * 检测数字是否为双精度Double
     * <p>
     * 只要有一个字符为小数点则该数字类型则不为整型
     * 或者数字超过int的上限或低于int的下限
     * Integer 在解析时已经将上限下限小数点以及0开头的数字去0操作
     *
     * @param str 源String
     * @return boolean true-该String为double类型
     * @throws NullPointerException 输入的String为空
     */
    public boolean stringIsDouble(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要判断是否为String为Null");
        }
        Double strDouble = null;
        try {
            strDouble = Double.parseDouble(str);
        } catch (Exception e) {
            return false;
        }

        return true;

    }

    /**
     * string转换为Integer整形
     *
     * @param str 源String
     * @return Integer
     * @throws NullPointerException 输入的String为空
     */
    public int convertStringToInteger(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要转换为Integer的String为Null");
        }

        return Integer.parseInt(str);
    }

    /**
     * stringArray转换为Integer整形Array
     * 如果传入的array.length为0  则直接返回空intArray
     *
     * @param strArray 源String
     * @return IntegerArray
     * @throws NullPointerException 输入的String为空
     */
    public int[] convertStringArrayToIntegerArray(String[] strArray) throws Exception {
        if (strArray == null) {
            throw new NullPointerException("传入需要转换的StringArray为Null");
        }
        int[] intArray = new int[strArray.length];
        int[] zeroIntArray = new int[0];
        if (strArray.length == 0) {

            return zeroIntArray;
        }
        for (int i = 0; i < strArray.length; i++) {
            intArray[i] = convertStringToInteger(strArray[i]);
        }
        return intArray;
    }


    /**
     * stringArray转换为double浮点型Array
     * 如果传入的array.length为0  则直接返回空doubleArray
     *
     * @param strArray 源String
     * @return doubleArray
     * @throws NullPointerException 输入的String为空
     */
    public double[] convertStringArrayToDoubleArray(String[] strArray) throws Exception {
        if (strArray == null) {
            throw new NullPointerException("传入需要转换的StringArray为Null");
        }
        double[] zeroDoubleArray = new double[0];
        double[] doubleArray = new double[strArray.length];
        if (strArray.length == 0) {

            return zeroDoubleArray;
        }
        for (int i = 0; i < strArray.length; i++) {
            doubleArray[i] = convertStringToDouble(strArray[i]);
        }
        return doubleArray;
    }


    /**
     * string转换为Double浮点型
     *
     * @param str 源String
     * @return Double浮点型
     * @throws NullPointerException 输入的String为空
     */
    public double convertStringToDouble(String str) throws Exception {
        if (str == null || str.equalsIgnoreCase("")) {
            throw new NullPointerException("传入需要转换为Integer的String为Null");
        }
        double result = Double.parseDouble(str);
        return result;
    }


}
